package visual

import (
	"cgs-server/server"
	"cgs-server/server/base"
	"cgs-server/server/model"
	"errors"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"strings"
)

type VisualRepository interface {
	List(visual *Visual, user *model.User) ([]*Visual, error)
	Add(visual *Visual, collectionName string, user *model.User) (*mongo.InsertOneResult, error)
	base.Repository
	FindById(id primitive.ObjectID) (*Visual, error)
	FindByCategory(mdl *model.DataUserModel) ([]*Visual, error)

	// 查询租户下的所有应用
	FindByTenantId(tenantId string) ([]*Visual, error)

	// 修改visual的ownder
	UpdateOwner(mdl *model.DataUserModel) error
}

func NewVisualRepository() VisualRepository {
	return &visualRepository{
		base.RepositoryStruct{
			CollectionName: server.CgsPortalVisualCollectionName + "ThreeD",
		},
	}
}

// visual
type visualRepository struct {
	base.RepositoryStruct
}

func (v *visualRepository) List(visual *Visual, user *model.User) ([]*Visual, error) {
	if err := v.CheckDB(); err != nil {
		return nil, err
	}
	filter := bson.M{}
	visual.ResolveFilter(visual, user, &filter)
	opts := visual.ResolveOptions(nil)
	opts.Sort = bson.M{
		"updateTime": -1,
		"UpdateTime": -1,
	}
	result := []*Visual{}
	err := v.Mongo.FindMany(v.CollectionName, filter, &result, opts)
	return result, err
}

func (v *visualRepository) Add(visual *Visual, collectionName string, user *model.User) (*mongo.InsertOneResult, error) {
	if err := v.CreateDB(collectionName); err != nil {
		return nil, err
	}
	/*filter := bson.M{
		"ID": visual.IdObjID,
	}
	doc := bson.M{}
	// 查看是否这个视图的分类数据
	find, _ := v.Mongo.FindOne(server.CgsPortalCategoryCollectionName, filter, &doc)
	if find {
		return nil, errors.New("visual is already existed")
	}*/
	visual.ResolveEntity(visual, user)
	/*visualDoc := bson.M{
		"ID":         visual.IdObjID,
		"Password":   visual.Password,
		"Category":   visual.Category,
		"Status":     visual.Status,
		"Title":      visual.Title,
		"CreateTime": time.Now(),
		"UpdateTime": time.Now(),
		"ProjectID":  visual.ProjectObjID,
		"UserID": visual.UserId,
		"BackgroundUrl": visual.BackgroundUrl,
	}*/
	return v.Mongo.InsertOne(v.CollectionName, visual)
}

func (v *visualRepository) FindById(id primitive.ObjectID) (*Visual, error) {
	if err := v.CheckDB(); err != nil {
		return nil, err
	}
	filter := bson.M{
		"ID": id,
	}
	result := &Visual{}
	find, err := v.Mongo.FindOne(v.CollectionName, filter, result)
	if err != nil {
		return nil, err
	}
	if find {
		return result, nil
	}
	return nil, err
}

func (v *visualRepository) FindByCategory(mdl *model.DataUserModel) ([]*Visual, error) {
	if visual, ok := mdl.Data.(*Visual); ok {
		if err := v.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{
			"Category": visual.Category,
			//"UserID": user.ID,
		}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		visual.ResolveFilter(visual, mdl.User, &filter)
		var result []*Visual
		err := v.Mongo.FindMany(v.CollectionName, filter, &result)
		if err != nil {
			return nil, err
		}
		return result, nil
	} else {
		return nil, errors.New("Visual type error")
	}
}

func (v *visualRepository) Update(mdl *model.DataUserModel) error {
	if visualModel, ok := mdl.Data.(*Model); ok {
		if err := v.CheckDB(); err != nil {
			return err
		}

		visual := &visualModel.Visual
		filter := bson.M{
			"ID": visual.ID,
		}
		visual.ResolveFilter(visual, mdl.User, &filter)

		updateOpt := bson.M{
			"Password": visual.Password,
		}
		if visual.Title != "" && !strings.HasPrefix(visual.Title, "_") {
			updateOpt["Title"] = visual.Title
		}
		if visual.BackgroundUrl != "" {
			updateOpt["BackgroundUrl"] = visual.BackgroundUrl
		}
		if visual.Category != nil {
			updateOpt["Category"] = *visual.Category
		}
		if visual.OrgCategory != nil {
			updateOpt["orgCategory"] = *visual.OrgCategory
		}
		if visual.Status != nil {
			updateOpt["Status"] = *visual.Status
		}
		visual.ResolveUpdateCondition(visual, mdl.User, &updateOpt)
		update := bson.M{
			"$set": updateOpt,
		}
		_, err := v.Mongo.UpdateOne(v.CollectionName, filter, update)
		return err
	} else {
		return errors.New("VisualModel type error")
	}
}

// 删除视图
func (v *visualRepository) Delete(mdl *model.DataUserModel) error {
	if visualModel, ok := mdl.Data.(*Model); ok {
		if err := v.CheckDB(); err != nil {
			return err
		}

		visual := &visualModel.Visual
		filter := bson.M{
			"ID": visual.ID,
		}
		visual.ResolveFilter(visual, mdl.User, &filter)
		_, err := v.Mongo.DeleteOne(v.CollectionName, filter)
		return err
	} else {
		return errors.New("VisualModel type error")
	}
}

// 视图详情
func (v *visualRepository) FindOne(mdl *model.DataUserModel) (interface{}, error) {
	if visualModel, ok := mdl.Data.(*Model); ok {
		if err := v.CheckDB(); err != nil {
			return nil, err
		}
		visual := &visualModel.Visual
		filter := bson.M{
			"ID": visual.ID,
		}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		visual.ResolveFilter(visual, mdl.User, &filter)
		result := &Visual{}
		_, err := v.Mongo.FindOne(v.CollectionName, filter, result)
		return result, err
	} else {
		return nil, errors.New("VisualModel type error")
	}
}

// 分页列表
func (v *visualRepository) Find(mdl *model.DataUserModel) (interface{}, error) {
	if visualModel, ok := mdl.Data.(*Model); ok {
		if err := v.CheckDB(); err != nil {
			return nil, err
		}
		visual := &visualModel.Visual
		filter := bson.M{
			/*"$or": bson.A{
				bson.M{
					"UserID": mdl.User.UserId.Hex(),
				},
				bson.M{
					"createUser": mdl.User.UserId.Hex(),
				},
			},*/
			"Category": visualModel.Visual.Category,
		}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		visual.ResolveFilter(visual, mdl.User, &filter)
		opts := visual.ResolveOptions(mdl.Page)
		opts.Sort = bson.M{
			"updateTime": -1,
			"UpdateTime": -1,
		}
		result := []*Visual{}
		//result := bson.A{}
		err := v.Mongo.FindMany(v.CollectionName, filter, &result, opts)
		return result, err
	} else {
		return nil, errors.New("VisualModel type error")
	}
}

// 总数
func (v *visualRepository) Count(mdl *model.DataUserModel) (int64, error) {
	if visualModel, ok := mdl.Data.(*Model); ok {
		if err := v.CheckDB(); err != nil {
			return 0, err
		}
		visual := &visualModel.Visual
		filter := bson.M{
			"Category": visualModel.Visual.Category,
		}
		if mdl.User != nil {
			filter = bson.M{
				"$or": bson.A{
					bson.M{
						"UserID": mdl.User.UserId.Hex(),
					},
					bson.M{
						"createUser": mdl.User.UserId.Hex(),
					},
				},
				"Category": visualModel.Visual.Category,
			}
		}

		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		visual.ResolveFilter(visual, mdl.User, &filter)
		count, err := v.Mongo.Count(v.CollectionName, filter)
		return count, err
	} else {
		return 0, errors.New("VisualModel type error")
	}
}

func (v *visualRepository) FindByTenantId(tenantId string) ([]*Visual, error) {
	if err := v.CheckDB(); err != nil {
		return nil, err
	}
	filter := bson.M{
		"tenantId": tenantId,
		"$or": bson.A{
			bson.M{
				"isDeleted": 0,
			},
			bson.M{
				"isDeleted": nil,
			},
		},
	}
	results := []*Visual{}
	err := v.Mongo.FindMany(v.CollectionName, filter, &results)
	if err != nil {
		return nil, err
	}
	return results, nil
}

func (v *visualRepository) UpdateOwner(mdl *model.DataUserModel) error {
	if visual, ok := mdl.Data.(*Visual); ok {
		if err := v.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"ID": visual.ID,
		}
		update := bson.M{
			"$set": bson.M{
				"owner":    visual.Owner,
				"tenantId": mdl.User.GetTenantId(),
			},
		}
		_, err := v.Mongo.UpdateMany(v.CollectionName, filter, update)
		return err
	} else {
		return model.NewTypeError("visual")
	}
}
